package com.qianfeng.websocket;

//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼                  BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//  


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by Jackiechan on 2022/5/31 9:35
 * 这个类就是处理websocket请求的,类似于我们的servlet类
 * 当前类的对象是一个多例对象,每次来一个请求,就会创建一个对象
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */
@ServerEndpoint("/websocket/{name}")
public class MyWebsocketClient {

    private String name;
    private Session session;

    //创建一个map,用于保存所有的客户端
    private static Map<String, Session> allClients = new ConcurrentHashMap<>();
    private ObjectMapper objectMapper = new ObjectMapper();

    //servlet是有生命周期方法的,websocket也有声明周期方法
    //建立连接的时候,收到消息的时候,出现错误的时候, 断开连接的时候

    /**
     * 当建立连接的时候执行的
     * @param name 就是我们上面定义的地址中的name占位符的具体数据
     * @param session 当前的会话对象,也就是谁和我们建立了连接,我们必须保存这个会话
     */
    @OnOpen
    public void onOpen(@PathParam("name") String name, Session session) {
        //数据必须要保存,因为数据不保存将变的毫无意义
        System.err.println("MyWebsocketClient中的方法onOpen 执行了------>"+name+"=====>"+session);
        allClients.put(name, session);
        this.name = name;
        this.session = session;
    }

    /**
     * 这个方法的意思是当服务器收到客户端给我们发送的消息的时候,具体做什么取决于业务要求
     * @param session 当前发送消息的是谁
     * @param message 发送的内容是什么
     */
    @OnMessage
    public void onMessage(Session session, String message) {
        System.err.println("MyWebsocketClient中的方法onMessage 执行了"+"---->"+session+"=======>"+message);
        //考虑我们的具体的业务, 假如说我们当前的主要业务是用作网页聊天
        //按照我们的约定,在这里收到的消息应该是一个json格式的数据,我们只需要解析出来,从对应的key中获取到数据即可
        //我们约定的收消息的key是toUser, 消息的内容是msg
        try {
            Map<String,String> map = objectMapper.readValue(message, Map.class);
            //获取到收消息的人
            String toUser = map.get("toUser");
            //获取消息的内容
            String msg = map.get("msg");
            //找到对应的收消息的人的会话
            Session toSession = allClients.get(toUser);
            if (toSession != null&&toSession.isOpen()) {
                //会话必须存在并且是打开的状态才会发送消息
                toSession.getAsyncRemote().sendText("收到来自于:" + name + " 的消息,内容是:" + msg);
            }else{
                //应该将数据保存起来,当客户端建立连接之后查询下信息,给客户端发送过去
                session.getAsyncRemote().sendText("对方不在线");
            }

        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 当会话关闭的时候
     * @param session 关闭的会话,其实就是执行当前方法的类对象对应的连接
     */
    @OnClose
    public void onClose(Session session) {
        System.err.println("MyWebsocketClient中的方法onClose 执行了"+"---->"+session);
        //从保存所有客户端的地方移除当前会话
        allClients.remove(name);//这里写name的 原因就是因为每个会话都是一个单独的MyWebsocketClient对象
    }


    /**
     * 当出现错误的时候,
     * @param session 出现错误的坏话
     * @param throwable 出现的 错误是什么
     */
    @OnError
    public void onError(Session session, Throwable throwable) {
        System.err.println("MyWebsocketClient中的方法onError 执行了" + "---->" + session + "======>" + throwable.getMessage());
        allClients.remove(name);
    }
}
